6
  • 现象:直接用=的方式把一个对象赋值给另一个对象,会导致修改新对象时,原对象也发生变化

    var obj1 = {'name': '1111'};
    var obj2 = obj1;
    obj2.name = '2222';
    console.log(obj1.name); //'2222'
  • 原因:JavaScript 中对象的赋值是默认引用赋值的(两个对象指向相同的内存地址)

一、Object.assign()拷贝对象

代码演示

// 使用 Object.assign() 方法复制对象
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}

obj2.a = 2;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}}

obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}

不足之处

  • 可以看到当修改obj2.b.c的值时,原对象obj1.b.c也跟着发生了变化,Object.assign()只是让对象里第一层的数据没有了关联性,但是对象内的对象则跟被复制的对象有着关联性的。
  • Object.assign(obj) --浅拷贝
    Object.assign({},obj) --只有第一层深拷贝 (ES6中扩展运算符...也是如此)

二、JSON.parse(JSON.stringify(obj))

代码演示

var function cloneObjectFn (obj){
    return JSON.parse(JSON.stringify(obj))
}

var obj1={a:2,b{c:0}}
var obj2=cloneObjectFn(obj1)
console.log(obj2)    // {a:2,b{c:0}}

不足之处

使用场景限制:obj属性不能是function、RegExp等,JSON序列化时会造成属性丢失:
image

三、原生JS实现深拷贝

// 定义一个深拷贝函数  接收目标target参数
function deepClone(target) {
    // 定义一个变量
    let result;
    // 如果当前需要深拷贝的是一个对象的话
    if (typeof target === 'object') {
        // 如果是一个数组的话
        if (Array.isArray(target)) {
            result = []; // 将result赋值为一个数组,并且执行遍历
            for (let i in target) {
                // 递归克隆数组中的每一项
                result.push(deepClone(target[i]))
            }
         // 判断如果当前的值是null的话;直接赋值为null
        } else if (target === null) {
            result = null;
         // 判断如果当前的值是一个RegExp对象的话,直接赋值 
        } else if (target.constructor === RegExp) {
            result = target;
        } else {
            // 否则是普通对象,直接for in循环,递归赋值对象的所有值
            result = {};
            for (let i in target) {
                result[i] = deepClone(target[i]);
            }
        }
    } else {
        // 如果不是对象的话,就是基本数据类型,那么直接赋值
        result = target;
    }
    // 返回最终结果
    return result;
}

PS. JS中function也是引用类型,但是函数名仅仅是指向该函数的指针,换句话说,一个函数可能会有多个名字

function sum(num1, num2){
  return num1 + num2;
}
console.log(sum(10, 10));// 20
 
var anotherSum = sum; // 此时有两个变量sum和anotherSum同时指向该函数(该函数此时有俩名字)
console.log(anotherSum(10, 10));// 20
 
sum = null; // sum置为空后,此时只有anotherSum指向该函数(该函数只有一个名字anotherSum)
console.log(anotherSum(10, 10));// 20

如上:代码中首先定义了一个名为sum的函数,用于求两个数的和。然后,又声明了变量anotherSum,赋值为sum,此时anotherSumsum就指向了同一个函数,因此anotherSum()也正常返回了结果。即使切断sum与函数对象的引用关系,也不会影响anotherSum

四、第三方提供的深拷贝方法

  • 写angularJS的时候用angular.copy()
  • 现在常用的是lodash.cloneDeep(),当然类似方法还有很多,符合自己习惯就好
  • 更多详细内容请参考:https://www.cnblogs.com/c2016...

星不克
52 声望2 粉丝

一蓑烟雨任平生